package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.mq.message.SignInMessage;
import com.tianji.learning.service.IPointsRecordService;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author Yandel
 * @since 2025-05-26
 */
@Service
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {
    /**
     * 添加积分记录
     *
     * @param msg  传来的msg信息
     * @param type 积分类型
     */
    @Override
    public void addPointsRecord(SignInMessage msg, PointsRecordType type) {
        if (msg.getUserId() == null || msg.getPoints() == null) {
            return;
        }
        int realPoints = msg.getPoints();//代表实际可以增加的积分
        //判断改积分是否有上限     疑问？怎么知道积分上限？---->枚举中定义了上限
        int maxPoints = type.getMaxPoints();//积分类型上限
        //在监听到消息通知后，不能说直接保存积分明细到数据库。因为积分规则中很多类型的积分是有上限的
        //因此，我们需要在保存到数据库之前，先判断是否超过积分上限。
        if (maxPoints > 0) {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime begin = DateUtils.getDayStartTime(now);
            LocalDateTime end = DateUtils.getDayEndTime(now);
            //判断是否有上限 如果有上限  查询该用户  该积分类型  [今日已得积分]    查询表：points_record  userId type
            QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
            wrapper.select("sum(points) as totalPoints")//由于有聚合函数，不支持lambda形式，如果硬写，
                    .eq("user_id", msg.getUserId())
                    .eq("type", type)
                    .between("create_time", begin, end);
            Map<String, Object> map = this.getMap(wrapper);
            int currentPoints = 0;//当前用户盖几份类型，已得积分
            if (map != null) {
                BigDecimal totalPoints = (BigDecimal) map.get("totalPoints");
                currentPoints = totalPoints.intValue();
            }
            //判断已得积分是否超过上限
            if (currentPoints >= maxPoints) {
                //说明积分上限
                return;
            }
            if (currentPoints + realPoints > maxPoints) {
                realPoints = maxPoints - currentPoints;
            }
        }
        //保存积分
        PointsRecord record = new PointsRecord();
        record.setUserId(msg.getUserId());
        record.setType(type.getValue());
        record.setPoints(realPoints);
        this.save(record);

    }


/*     讲义写法   使用了lambda形式+Sql
    private int queryUserPointsByTypeAndDate(Long userId, PointsRecordType type, LocalDateTime begin, LocalDateTime end) {
        //查询获取今日积分
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(PointsRecord::getUserId, userId)
                .eq(type != null, PointsRecord::getType, type)
                .between(begin != null && end != null, PointsRecord::getCreateTime, begin, end);
        Integer points = getBaseMapper().queryUserPointsByTypeAndDate(wrapper);

        return points == null ? 0 : points;
    }*/

    @Override
    public List<PointsStatisticsVO> queryMyTodayPoints() {
        //获取用户id
        Long userId = UserContext.getUser();
        // 查询积分表 points_record 条件:user_id
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
        LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);

        //查询 SELECT  type,sum(points)  from  points_record
        //WHERE user_id = 2 and  create_time BETWEEN '2025-5-27 00:00:01' AND '2025-5-27 23:59:59'
        //GROUP BY type
        //查询结果为：
        //type      sum(options)
        //1          12
        //2          1
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        //利用PointsRecord实体类中userId字段暂存 但是注意暂存字段类型要求字段类型匹配
        wrapper.select("type", "sum(points) as points");//根据type分组
        wrapper.eq("user_id", userId);
        wrapper.between("create_time", dayStartTime, dayEndTime);
        wrapper.groupBy("type");
        List<PointsRecord> list = this.list(wrapper);
        if (CollUtils.isEmpty(list)) {
            return CollUtils.emptyList();
        }
        //封装vo返回
        List<PointsStatisticsVO> voList = new ArrayList<>();
        for (PointsRecord record : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            //type类型枚举
            PointsRecordType rypeEnum = PointsRecordType.of(record.getType());
            if (rypeEnum != null){
                vo.setType(rypeEnum.getDesc());
                vo.setMaxPoints(rypeEnum.getMaxPoints());
            }
            vo.setPoints(record.getPoints());
            voList.add(vo);
        }
        return voList;
    }
}
